package com.supplychainapi.filter;

import com.alibaba.fastjson.JSONObject;
import com.supplychainapi.common.CommonCode;
import com.supplychainapi.common.ServiceResponse;
import com.supplychainapi.utils.DateUtils;
import com.supplychainapi.utils.MD5Utils;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedReader;
import java.io.IOException;
import java.util.*;

/**
 * 请求过滤器
 * 
 * @author maokaikai
 * @Time 2017年9月1日 下午1:43:11
 */

@WebFilter(filterName = "requestFilter", urlPatterns = "/*")
public class RequestFilter implements Filter {

	private Logger logger = LogManager.getLogger(RequestFilter.class);
	
	@Autowired
	private Environment env;

	public static final Map<String, String> sorces_map = new HashMap<String, String>();
	static {
		sorces_map.put("MT", "移动端");
		sorces_map.put("MT_M", "移动端掌柜");
		sorces_map.put("MT_W", "移动端小二 ");
		sorces_map.put("WPS", "windowsPOS");
		sorces_map.put("APS", "安卓POS");
		sorces_map.put("WPS_F", "windowsPOS 快餐");
		sorces_map.put("WPS_M", "windowsPOS 正餐");
		sorces_map.put("APS_F", "安卓POS 快餐");
		sorces_map.put("APS_M", "安卓POS 正餐");
		sorces_map.put("WPD", "windows打服");
		sorces_map.put("YUN_P", "云打印");
	}

	/**
	 * 封装，不需要过滤的list列表
	 */
	protected static List<String> no_filter_list = new ArrayList<String>();
	static {
		no_filter_list.add("/");
	}

	@Override
	public void init(FilterConfig filterConfig) throws ServletException {

	}

	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) servletRequest;
		HttpServletResponse response = (HttpServletResponse) servletResponse;
		String url = request.getRequestURI().substring(request.getContextPath().length());

		logger.info("请求url：{}", url);

		// 不需要过滤
		if (isInclude(url)) {
			if(url.equals("/")) {
				return;
			}
			chain.doFilter(request, response);
		} else {
			Map<String, String> param_map = new HashMap<String, String>();

			response.setCharacterEncoding("UTF-8");
			response.setContentType("application/json; charset=utf-8");

			ServiceResponse<String> serviceResponse = new ServiceResponse<String>();
			// 获取请求参数
			if (request.getContentType() != null && request.getContentType().contains("json")) {
				String jsonStr = readData(request);
				if (StringUtils.isNotBlank(jsonStr)) {
					JSONObject jsonObject = JSONObject.parseObject(jsonStr);
					Set<String> keyset = jsonObject.keySet();

					Iterator<String> it = keyset.iterator();
					while (it.hasNext()) {
						String json_key = it.next();
						Object json_value = jsonObject.get(json_key);
						param_map.put(json_key, json_value.toString());
					}
				}else {
					Map<String, String[]> param_maps = request.getParameterMap();
					for (Map.Entry<String, String[]> entry : param_maps.entrySet()) {
						if (entry.getValue() != null && entry.getValue().length > 0) {
							param_map.put(entry.getKey(), entry.getValue()[0]);
						} else {
							param_map.put(entry.getKey(), "");
						}
					}
				}
			} else {
				// 获取url后跟的参数
				if (StringUtils.isNotBlank(request.getQueryString())) {
					// pay_order=S20170816000066&sign=F8D3862802C5C85D231593E78BA6D4AA
					String[] arr_param = request.getQueryString().split("&");
					for (String param_ : arr_param) {
						String[] param_arr = param_.split("=");
						param_map.put(param_arr[0], param_arr[1]);
					}
				} else {
					Map<String, String[]> param_maps = request.getParameterMap();
					for (Map.Entry<String, String[]> entry : param_maps.entrySet()) {
						if (entry.getValue() != null && entry.getValue().length > 0) {
							param_map.put(entry.getKey(), entry.getValue()[0]);
						} else {
							param_map.put(entry.getKey(), "");
						}
					}
				}
			}

			// 签名验证
			if (param_map != null && param_map.size() > 0) {
				// 数据来源为空
				if (param_map.get("source") == null) {
					serviceResponse.setCode(CommonCode.SOURCE_NOT_NULL.getCode());
					serviceResponse.setMessage(CommonCode.SOURCE_NOT_NULL.getDesc());
					log_response(response, serviceResponse);
					return;
				}
				// 提交时间不能为空
				if (param_map.get("subTime") == null) {
					serviceResponse.setCode(CommonCode.SUBTIME_NOT_NULL.getCode());
					serviceResponse.setMessage(CommonCode.SUBTIME_NOT_NULL.getDesc());
					log_response(response, serviceResponse);
					return;
				}
				// 时间格式不正确
				if (!DateUtils.isValidDate(param_map.get("subTime").toString())) {
					serviceResponse.setCode(CommonCode.SUBTIME_ERROR.getCode());
					serviceResponse.setMessage(CommonCode.SUBTIME_ERROR.getDesc());
					log_response(response, serviceResponse);
					return;
				}
				// 数据来源不正确
				if (sorces_map.get(param_map.get("source").toString()) == null) {
					serviceResponse.setCode(CommonCode.SOURCE_ERROR.getCode());
					serviceResponse.setMessage(CommonCode.SOURCE_ERROR.getDesc());
					log_response(response, serviceResponse);
					return;
				}

				String sign = "";
				// 获取参数
				Map<String, String> map_sign = new HashMap<String, String>();
				for (Map.Entry<String, String> entry : param_map.entrySet()) {
					if (StringUtils.equals(entry.getKey(), "sign")) {
						sign = entry.getValue();
					} else {
						map_sign.put(entry.getKey(), entry.getValue());
						request.setAttribute(entry.getKey(), entry.getValue());
					}
				}
				logger.info("签名 params: {}", map_sign.toString());
				// 服务端签名
				String sign_server = MD5Utils.getSign(map_sign, env.getProperty("posKey"));

				logger.info("服务器签名: " + sign_server);

				// 签名验证
				if (StringUtils.equals(sign, sign_server)) {
					logger.info("请求 验证通过: {}", request.getRequestURL());
					param_map.clear();
					chain.doFilter(request, response);
				} else {
					logger.info("请求签名验证证失败: {}", param_map.toString());
					serviceResponse.setCode(CommonCode.SIGN_FAIL.getCode());
					serviceResponse.setMessage(CommonCode.SIGN_FAIL.getDesc());
					log_response(response, serviceResponse);
					return;
				}

			} else {
				logger.info("签名 params: {}", param_map.toString());
				serviceResponse.setCode(CommonCode.SIGN_FAIL.getCode());
				serviceResponse.setMessage(CommonCode.SIGN_FAIL.getDesc());
				log_response(response, serviceResponse);
				return;
			}
		}
	}

	private void log_response(HttpServletResponse response, ServiceResponse<String> serviceResponse) throws IOException {
		response.getWriter().write(serviceResponse.toString());
		logger.info(serviceResponse.toString());
	}

	@Override
	public void destroy() {

	}

	/**
	 * 是否需要过滤
	 * 
	 * @param url
	 * @return
	 */
	private boolean isInclude(String url) {
		for (String url_str : no_filter_list) {
			if (StringUtils.equals(url_str, url)) {
				return true;
			}
		}
		return true;
//		return !(url.contains("/pos/") || url.contains("/phone/"));
	}

	public String readData(HttpServletRequest request) {
		BufferedReader br = null;
		try {
			StringBuilder ret;
			br = request.getReader();

			String line = br.readLine();
			if (line != null) {
				ret = new StringBuilder();
				ret.append(line);
			} else {
				return "";
			}

			while ((line = br.readLine()) != null) {
				ret.append('\n').append(line);
			}

			return ret.toString();
		} catch (IOException e) {
			throw new RuntimeException(e);
		} finally {
			if (br != null) {
				try {
					br.close();
				} catch (IOException e) {
					logger.error(e.getMessage(), e);
				}
			}
		}
	}

}